<?php
//判断是否非法访问站点文件.
defined("APP_VERSION") OR die("No Access");
//引入系统配置文件.
$core_config = require(APP_ROOT.DIRECTORY_SEPARATOR."config.php");
//系统缓存.
$sys_cache = new SysCache();
//自动加载model文件.
function __autoload($class_name) {
	if (substr($class_name, -5) == 'Model') {
		include APP_ROOT.DIRECTORY_SEPARATOR.'model'.DIRECTORY_SEPARATOR."{$class_name}.class.php";
	}
}

class DbModel {
	/**
	 * @var CoreDb 
	 */
	protected $db = NULL;
	
	protected $db_prefix = NULL;
	
	public function __construct() {
		if ($this->db == NULL) {
			$this->db = Db::getDbInterface();
		}
		
		$this->db_prefix = $GLOBALS['core_config']['db_prefix'];
		if (method_exists($this, '_init')) $this->_init();
	}
}

//数据库基类
final class Db extends CoreDb {
	private static $db = NULL;
	
	protected $link = NULL;
	/**
	 * 连接数据库.
	 * @param string $hostname	数据库主机地址
	 * @param string $username  数据库用户名
	 * @param string $password  数据库用户密码
	 * @param string $database  数据库.
	 * @param string $charset   数据库编码.默认UTF8
	 * @return void
	 */
	public function __construct($hostname, $username, $password, $database, $charset = "utf8") {
		$this->link = mysql_connect($hostname, $username, $password);
		if ($this->link == FALSE) {
			throw new Exception("错误信息:".mysql_error(), mysql_errno());
		}
		mysql_set_charset($charset, $this->link);
		mysql_select_db($database, $this->link);
	}

	/**
	 * 获取数据库操作接口 
	 */
	public static function getDbInterface() {
		if (Db::$db == NULL) {
			Db::$db = new Db($GLOBALS['core_config']['db_host'],$GLOBALS['core_config']['db_user'],$GLOBALS['core_config']['db_pass'],$GLOBALS['core_config']['db_name']);
		}
		return Db::$db;
	}

	/**
	 * 执行SQL语句. 
	 */
	public function query($query) {
		$resource = mysql_query($query, $this->link);

		if ($resource == FALSE) {
			throw new Exception("错误语句:".$query, mysql_errno());
		}

		return $resource;
	}

	/**
	 * 查找单条记录. 
	 */
	public function findOne($sql) {
		if (strpos($sql, "LIMIT") === FALSE) {
			$sql = $sql . " LIMIT 1";
		}
		$result = $this->query($sql);
		return mysql_fetch_array($result);
	}

	/**
	 * 查找多条记录. 
	 */
	public function findAll($sql) {
		$result = $this->query($sql);

		$rows = array();
		while($rows[] = mysql_fetch_array($result, MYSQL_ASSOC)){}
		mysql_free_result($result);
		array_pop($rows);
		return $rows;
	}

	public function sqlCountNumber($sql) {
		$result = $this->query($sql);
		return mysql_fetch_row($result);
	}
	
	//执行SQL语句.
	public function exec($query) {
		return $this->query($query);
	}
	
	//Last Insert Id
	public function lastInsertId() {
		return mysql_insert_id($this->link);
	}
	
	/**
	 * 转换SQL与剧中的字符
	 * @param string $string
	 * @return string 
	 */
	public function escape($string) {
		return mysql_real_escape_string($string, $this->link);
	}

	/**
	 * 关闭数据库连接.
	 */
	public function __destruct() {
		mysql_close($this->link);
	}
}


/**
 * 数据库抽象类.
 */
abstract class CoreDb {
	/**
	 * 连接数据库.
	 * @param string $hostname	数据库主机地址
	 * @param string $username  数据库用户名
	 * @param string $password  数据库用户密码
	 * @param string $database  数据库.
	 * @param string $charset   数据库编码.默认UTF8
	 * @return void
	 */
	abstract public function __construct($hostname, $username, $password, $database, $charset = "utf8");

	/**
	 * 执行sql语句.
	 * @param string $query sql语句.
	 * @return resource
	 */
	abstract public function query($query);

	/**
	 * 查找单条数据记录.
	 * @param string $sql sql语句.
	 * @return array
	 */
	abstract public function findOne($sql);

	/**
	 * 查找多条数据。
	 * @param string $sql sql语句.
	 * @return array
	 */
	abstract public function findAll($sql);

	/**
	 * 查看SQL语句影响的行数.
	 * @param string $sql  sql语句.
	 * @return integer
	 */
	abstract public function sqlCountNumber($sql);
	
	//执行数据操作的SQL
	abstract public function exec($query);
	
	abstract public function lastInsertId();
	
	abstract public function escape($string);
}

//SESSION会话处理类.
ini_set('session.save_handler', 'user');
$core_session = new CoreSession();
session_set_save_handler(
	array($core_session, "open"),
	array($core_session, "close"),
	array($core_session, "read"),
	array($core_session, "write"),
	array($core_session, "destroy"),
	array($core_session, "gc")
);
//下面这个必须添加,否则程序页面运行完毕,会继续回到Session类,此时db类数据连接已关闭.会出错.
register_shutdown_function('session_write_close');

/**
 * 整个cms的核心,运行cms正常运转. 
 */
function core_start() {
	//默认的action为index
	$action = isset($_GET['c']) ? strtolower($_GET['c']) : 'index';
	//默认执行action中的index方法.
	$action_method = isset($_GET['m']) ? strtolower($_GET['m']) : 'index';
		
	if ($GLOBALS['sys_cache']->getCache() != FALSE) {
		$GLOBALS['sys_cache']->display();
	} else {
		//action 的类名.
		$action_class_name = ucfirst($action)."Action";
		//action 文件.
		$action_file = APP_ROOT.DIRECTORY_SEPARATOR."action".DIRECTORY_SEPARATOR.$action_class_name.".class.php";
		//如果action文件不存在,说明访问的action文件不存在.那么执行错误Action.
		if (file_exists($action_file) == FALSE) {
			//引入ErrorAction.class.php,进行错误页面处理.
			$error_action_file = APP_ROOT.DIRECTORY_SEPARATOR."action".DIRECTORY_SEPARATOR."ErrorAction.class.php";
			//处理错误请求的页面.
			if (file_exists($error_action_file) == FALSE) {
				throw new Exception($error_action_file."不存在.", 10010);
			}
			include($error_action_file);
			$error_action = new ErrorAction();
			$error_action->index();
		} else {
			//引入控制器.
			include($action_file);
			//实例化控制器.
			$core_action = new $action_class_name();
			//告诉控制器当前调用的是哪个方法.
			$core_action->action_method = $action_method;
			//方法不存在,则执行错误页面.
			if (method_exists($core_action, $action_method) == FALSE) {
				$action_method = 'error';
			}
			//处理页面数据,输出页面.
			call_user_method($action_method, $core_action);
		}
	}
}

/**
 * 核心的Action处理类.
 * 用以初始处理Action的请求和数据。 
 */
class CoreAction {
	/**
	 * 存储模版中的变量信息. 
	 */
	protected $data = array();
	
	/**
	 * @var CoreDb 
	 */
	public $db = NULL;
	
	public function __construct() {
		$this->initAction();
	}
	
	//初始化
	public function initAction(){}
	
	public function message($url, $content = '', $title = '提示信息') {
		include(APP_TEMPLATE_ROOT.DIRECTORY_SEPARATOR."Comm".DIRECTORY_SEPARATOR."message.php");
		exit;
	}
	
	/**
	 * 未找到的页面. 
	 */
	public function error() {
		echo 'error ff';
	}
	
	/**
	 * 取得URL信息. 
	 * @param  string  $c
	 * @param  string  $m
	 * @param  array   $params
	 * @return string
	 */
	public function baseUrl($c = 'index', $m = 'index', $params = array()) {
		$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
		if ($c == 'index' && $m == 'index') {
			$url = str_replace('index.php', '', $url);
		} else {
			$url .= "?c={$c}&m={$m}";
		}
		if (is_array($params) && count($params)) {
			foreach ($params as $p_key => $p_val) {
				$url .= "&{$p_key}={$p_val}";
			}
		}
		return $url;
	}
	
	public function redirect($c, $m, $params = array()) {
		$url = $this->baseUrl($c, $m, $params);
		header('Location:'.$url);
		exit;
	}
	
	/**
	 * 将字符进行html转义.
	 * @param data $mixdata  要转义的字符或者数组.
	 * @return string/array  返回字符或者数组
	 */
	public function scriptToHtml($mixdata) {
		if (is_array($mixdata)) {
			foreach ($mixdata as $d_key => $d_val) {
				$mixdata[$d_key] = $this->scriptToHtml($d_val);
			}
		} else if (is_string($mixdata)) {
			return addslashes($mixdata);
		}
		
		return $mixdata;
	}
	
	/**
	 * 将HTML转换为字符.
	 * @param data $mixdata html代码转换字符
	 * @return string/array 返回数组或者字符 
	 */
	public function htmlToScript($mixdata) {
		if (is_array($mixdata)) {
			foreach ($mixdata as $d_key => $d_val) {
				$mixdata[$d_key] = $this->scriptToHtml($d_val);
			}
		} else if (is_string($mixdata)) {
			return htmlspecialchars($mixdata);
		}
		
		return $mixdata;
	}
	
	/**
	 * 显示模版内容. 
	 * @param string $template_file 模版文件名字
	 * @param string $cache_time    模版缓存时间.  默认一个小时.
	 * @return string
	 */
	public function display($template_file = '', $cache_time = 3600) {
		$content = $this->fetch($template_file, $cache_time);
		$GLOBALS['sys_cache']->setCache($content);
		echo $content;
	}
	
	/**
	 * 取得模版内容. 
	 */
	public function fetch($template_file = '', $cache_time = 3600) {
		//页面UTF8编码
		header("Content-type: text/html; charset=utf-8");
		foreach ($this->data as $d_key => $d_val) {
			$this->data[$d_key] = $this->scriptToHtml($d_val);
		}
		//未指定模版文件,默认为当前method.
		if ($template_file == '') {
			$template_file = $this->action_method.".php";
		}
		
		$template_file = $GLOBALS['core_config']['template_dir'].DIRECTORY_SEPARATOR.
		str_replace("Action", "", get_class($this)).DIRECTORY_SEPARATOR.$template_file;
		
		if (file_exists($template_file) == FALSE) {
			die("模版文件不存在");
		}
		
		ob_start();
		//引入模版.
		include $template_file;
		$content = ob_get_contents();
		ob_end_clean();
		//输出模版.
		return $content;		
	}
	
	/**
	 * 公共块部分加载.
	 * @param string $action_file 要加载的页面.
	 * @return string. 
	 */
	public function templateBlock($action_file = '') {
		$data = explode(':', $action_file);
		include(APP_TEMPLATE_ROOT.DIRECTORY_SEPARATOR.$data[0].DIRECTORY_SEPARATOR.$data[1].'.php');
	}
}

class SysCache {
	//缓存文件目录.
	protected $cache_dir;
	
	//缓存文件名.
	protected $cache_file;
	
	protected $cache = false;
	
	//设置缓存
	public function __construct(){
		$this->cache_dir = APP_ROOT.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR;
		if (file_exists($this->cache_dir) == FALSE) mkdir($this->cache_dir, 0777);
		$this->cache_file = $this->cache_dir.md5($_SERVER['REQUEST_URI']);
	}
	
	public function setCache($content) {
		if($this->cache) file_put_contents($this->cache_file, $content);
	}
	
	public function getCache() {
		return $this->cache && file_exists($this->cache_file) ? $this->cache_file : false;
	}
	
	public function display() {
		ob_start();
		include($this->cache_file);
		$content = ob_get_contents();
		ob_end_clean();
		echo $content;
	}
}

/**
 * SESSION处理. 
 */
class CoreSession {
	/**
	 * @var SessionModel
	 */
	private $session = NULL;
	
	public function __construct() {
		if (($this->session instanceof SessionModel) == false) {
			$this->session = new SessionModel();
		}
	}
	
	public function open($savePath, $sessionName) {
		$this->session->openSession($savePath, $sessionName);
		return true;
	}
	
	public function close() {
		$this->session->sessionClose();
		return true;
	}
	
	public function read($sessionId) {
		return $this->session->sessionRead($sessionId);
	}
	
	public function write($sessionId, $data) {
		$session_data = $this->read($sessionId);
		$this->session->sessionWrite($sessionId, $data);
	}
	
	public function destroy($sessionId) {
		$this->session->sessionDestroy($sessionId);
	}
	
	//清楚超时的数据.
	public function gc($maxlifetime) {
		$this->session->sessionGc($maxlifetime);
	}
}